#!/bin/bash

# 钉钉群机器人的 Webhook 地址（未加签的原始地址）
DINGTALK_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxx"

# 钉钉群机器人的加签 secret
DINGTALK_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# 日志文件路径
LOG_FILE="/var/log/secure"

# 生成加签后的 Webhook URL
generate_signed_url() {
    local timestamp=$(date +%s%3N)  # 当前时间戳（毫秒）
    local sign=$(echo -ne "$timestamp\n$DINGTALK_SECRET" | openssl dgst -sha256 -hmac "$DINGTALK_SECRET" -binary | base64)
    sign=$(echo -n "$sign" | sed 's/+/%2B/g' | sed 's/\//%2F/g' | sed 's/=/%3D/g')  # URL 编码
    echo "$DINGTALK_WEBHOOK&timestamp=$timestamp&sign=$sign"
}

# 发送 Markdown 格式消息到钉钉群
send_dingtalk_message() {
    local message="$1"
    local signed_url=$(generate_signed_url)

    curl -s "$signed_url" \
        -H 'Content-Type: application/json' \
        -d "{
            \"msgtype\": \"markdown\",
            \"markdown\": {
                \"title\": \"SSH 登录监控\",
                \"text\": \"$message\"
            }
        }"
}

# 使用 tail -f 实时监控日志文件
tail -n 0 -f "$LOG_FILE" | awk -v dingtalk_secret="$DINGTALK_SECRET" -v dingtalk_webhook="$DINGTALK_WEBHOOK" '
# 生成加签后的 Webhook URL
function generate_signed_url() {
    cmd = "date +%s%3N"
    cmd | getline timestamp
    close(cmd)

    cmd = "echo -ne \"" timestamp "\\n" dingtalk_secret "\" | openssl dgst -sha256 -hmac \"" dingtalk_secret "\" -binary | base64"
    cmd | getline sign
    close(cmd)

    gsub(/\+/, "%2B", sign)
    gsub(/\//, "%2F", sign)
    gsub(/=/, "%3D", sign)

    return dingtalk_webhook "&timestamp=" timestamp "&sign=" sign
}

# 发送消息到钉钉群
function send_dingtalk_message(message) {
    signed_url = generate_signed_url()
    cmd = "curl -s \"" signed_url "\" -H '\''Content-Type: application/json'\'' -d '\''{\"msgtype\": \"markdown\", \"markdown\": {\"title\": \"SSH 登录监控\", \"text\": \"" message "\"}}'\''"
    system(cmd)
}

# 匹配包含以下关键字的日志行
/sshd.*(Connection closed by invalid user|Invalid user|Accepted (password|publickey)|Failed password)/ {
    # 提取时间（日志的前三个字段）
    time = $1 " " $2 " " $3

    # 提取主机名（日志的第 4 个字段）
    host = $4

    # 初始化变量
    user = ""
    ip = ""
    status = ""

    # 根据日志类型提取用户名、IP 地址和登录状态
    if ($0 ~ /Connection closed by invalid user/) {
        # 如果是 "Connection closed by invalid user" 类型的日志
        user = $9  # 用户名在第 9 个字段
        ip = $11   # IP 地址在第 11 个字段
        status = "登录失败"
    }
    else if ($0 ~ /Invalid user/) {
        # 如果是 "Invalid user" 类型的日志
        user = $8  # 用户名在第 8 个字段
        ip = $10   # IP 地址在第 10 个字段
        status = "登录失败"
    }
    else if ($0 ~ /Failed password/) {
        # 如果是 "Failed password" 类型的日志
        user = $9  # 用户名在第 9 个字段
        ip = $11   # IP 地址在第 11 个字段
        status = "登录失败"
    }
    else if ($0 ~ /Accepted (password|publickey)/) {
        # 如果是 "Accepted password" 或 "Accepted publickey" 类型的日志
        user = $9  # 用户名在第 9 个字段
        ip = $11   # IP 地址在第 11 个字段
        status = "登录成功"
    }

    # 输出解析结果并发送到钉钉群
    if (user != "" && ip != "") {
        # 格式化 Markdown 消息
        message = "### SSH 登录监控\n\n" \
                  "- **时间**: " time "\n" \
                  "- **主机名**: " host "\n" \
                  "- **用户名**: " user "\n" \
                  "- **IP**: " ip "\n" \
                  "- **状态**: " status
        print message  # 打印到控制台
        send_dingtalk_message(message)  # 发送到钉钉群
    }
}
'